﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Runtime.InteropServices;

namespace TestWinAPI.钩子
{
    public partial class HookTest : System.Web.UI.Page
    {
        private MyHook callProcHook = new MyHook(HookType.WH_CALLWNDPROC);
        private MyHook keyHook = new MyHook(HookType.WH_KEYBOARD);


        protected void Page_Load(object sender, EventArgs e)
        {
            keyHook.HookInvoked += new HookEventHandler(keyHook_HookInvoked);
            keyHook.Install();

            callProcHook.HookInvoked += new HookEventHandler(callProcHook_HookInvoked);
            callProcHook.Install();
        }

        private void keyHook_HookInvoked(object sender, HookEventArgs e)
        {
            if (e.key == Keys.F4 && e.bAltKey) //Alt + F4
            {
                this.WindowState = FormWindowState.Minimized;
            }
            else if (e.key == Keys.F3 && e.bAltKey)
            {
                this.WindowState = FormWindowState.Maximized;
            }
            else if (e.key == Keys.F5 && e.bAltKey)
            {
                this.WindowState = FormWindowState.Normal;
            }
        }


        private void callProcHook_HookInvoked(object sender, HookEventArgs e)
        {
            unsafe
            {
                CWPSTRUCT* message = (CWPSTRUCT*)e.lParam;
                if (message != null)
                {
                    if (message->message == WM_CLOSE)
                    {
                        (sender as MyHook).CallNextProc = false;
                        MessageBox.Show("程序即将关闭！");
                    }
                }
            }
        }



    }


    #region 消息结构体(参照WinUser.h中定义)
    /// <summary>
    /// 这个是windows内部传递过来的消息的结构
    /// </summary>
    public struct CWPSTRUCT
    {
        public IntPtr lparam;
        public IntPtr wparam;
        public int message;
        public IntPtr hwnd;
    }
    #endregion

    #region 钩子类型的枚举

    /// <summary>
    /// 钩子类型的枚举
    /// </summary>
    public enum HookType : int
    {
        WH_JOURNALRECORD = 0,
        WH_JOURNALPLAYBACK = 1,
        WH_KEYBOARD = 2,//监控按键事件
        WH_GETMESSAGE = 3,
        WH_CALLWNDPROC = 4,//在消息触发时执行
        WH_CBT = 5,
        WH_SYSMSGFILTER = 6,
        WH_MOUSE = 7,
        WH_HARDWARE = 8,
        WH_DEBUG = 9,
        WH_SHELL = 10,
        WH_FOREGROUNDIDLE = 11,
        WH_CALLWNDPROCRET = 12,
        WH_KEYBOARD_LL = 13,
        WH_MOUSE_LL = 14
    }
    #endregion

    #region 虚键值的定义(参照WinUser.h中定义)

    /// <summary>
    /// 虚键值的定义(参照WinUser.h中定义)
    /// </summary>
    public enum VirtualKeys
    {
        VK_SHIFT = 0x10,
        VK_CONTROL = 0x11,
        VK_MENU = 0x12,    //ALT
        VK_PAUSE = 0x13,
        VK_CAPITAL = 0x14
    }
    #endregion

    #region 钩子委托
    /// <summary>
    /// SetWindowsHookEx调用时的委托事件
    /// </summary>
    /// <param name="code"></param>
    /// <param name="wParam"></param>
    /// <param name="lParam"></param>
    /// <returns></returns>
    public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

    /// <summary>
    /// 自己的委托事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void HookEventHandler(object sender, HookEventArgs e);
    #endregion


    #region 钩子事件参数

    /// <summary>
    /// 是自己的委托事件中接受的事件参数
    /// </summary>
    public class HookEventArgs : EventArgs
    {
        public int HookCode;
        public IntPtr wParam;
        public IntPtr lParam;
        public Keys key;
        public bool bAltKey;
        public bool bCtrlKey;
    }
    #endregion


    #region 钩子类
    public class MyHook
    {
        #region 调用Windows API

        /// <summary>
        /// 注册一个钩子程序
        /// </summary>
        /// <param name="hook"></param>
        /// <param name="callback"></param>
        /// <param name="hMod"></param>
        /// <param name="dwThreadId"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);

        /// <summary>
        /// 释放钩子程序
        /// </summary>
        /// <param name="hhk"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);

        /// <summary>
        /// 调用钩子的后续事件处理
        /// </summary>
        /// <param name="hhk"></param>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// 得到所按的虚键
        /// </summary>
        /// <param name="nVirtKey"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        static extern short GetKeyState(VirtualKeys nVirtKey);
        #endregion

        #region 局部变量
        private IntPtr m_hook;
        private HookType m_hooktype;

        /// <summary>
        /// 实际的钩子处理程序
        /// </summary>
        private HookProc m_hookproc;

        private bool _bCallNext;

        public bool CallNextProc
        {
            get { return _bCallNext; }
            set { _bCallNext = value; }
        }

        #endregion

        public event HookEventHandler HookInvoked;

        public void Install()
        {
            m_hook = SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
        }

        public void Uninstall()
        {
            if (m_hook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(m_hook);
            }
        }

        public MyHook(HookType HookType)
        {
            m_hooktype = HookType;
            if (m_hooktype == HookType.WH_KEYBOARD)
            {
                m_hookproc = new HookProc(KeyHookProcedure);
            }
            else if (m_hooktype == HookType.WH_CALLWNDPROC)
            {
                m_hookproc = new HookProc(CallProcHookProcedure);
            }
        }

        protected int KeyHookProcedure(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code != 0)
            {
                return CallNextHookEx(m_hook, code, wParam, lParam);
            }

            if (HookInvoked != null)
            {
                Keys key = (Keys)wParam.ToInt32();
                HookEventArgs eventArgs = new HookEventArgs();
                eventArgs.key = key;
                eventArgs.lParam = lParam;
                eventArgs.wParam = wParam;
                eventArgs.HookCode = code;
                eventArgs.bAltKey = GetKeyState(VirtualKeys.VK_MENU) <= -127;
                eventArgs.bCtrlKey = GetKeyState(VirtualKeys.VK_CONTROL) <= -127;
                HookInvoked(this, eventArgs);
            }

            return CallNextHookEx(m_hook, code, wParam, lParam);
        }

        protected int CallProcHookProcedure(int code, IntPtr wParam, IntPtr lParam)
        {
            try
            {
                CallNextProc = true;
                if (HookInvoked != null)
                {
                    HookEventArgs eventArgs = new HookEventArgs();
                    eventArgs.lParam = lParam;
                    eventArgs.wParam = wParam;
                    eventArgs.HookCode = code;
                    HookInvoked(this, eventArgs);
                }

                if (CallNextProc)
                {
                    return CallNextHookEx(m_hook, code, wParam, lParam);
                }
                else
                {
                    //return 1;
                    return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                return 0;
            }
        }
    }
    #endregion

 

}
